package com.atguigu.gmall.web.all.service.impl;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.feign.cart.CartFeignClient;
import com.atguigu.gmall.feign.product.SkuInfoFeignClient;
import com.atguigu.gmall.feign.user.UserFeignClient;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.user.UserAddress;
import com.atguigu.gmall.web.all.service.OrderService;
import jodd.time.TimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.awt.geom.RectangularShape;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    CartFeignClient cartFeignClient;

    @Autowired
    UserFeignClient userFeignClient;

    @Autowired
    SkuInfoFeignClient skuInfoFeignClient;

    @Qualifier("corePool")
    @Autowired
    ThreadPoolExecutor executor;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public Map<String, Object> getOrderConfirmInfo(String userId) {

        HashMap<String, Object> map = new HashMap<>();
        //从controller--service的主线程的request信息
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        //防并发，线程安全，必须不可变
        final BigDecimal[] totalAmount = {new BigDecimal("0.0")};
        final AtomicInteger[] totalNum = {new AtomicInteger(0)};

        CompletableFuture<List<CartInfo>> listCompletableFuture = CompletableFuture.supplyAsync(() -> {

            //1、远程查询购物车服务，获取到购物车选中的所有商品列表
            //远程调用，异步的方式运行feign，请求信息会丢失--》看feign的拦截器
            //属于开了新线程，按照ThreadLocal存的,所以新线程自己存一个老请求就行了 TODO 下面也一样，异步远程
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<CartInfo> detailArrayList = cartFeignClient.cartListChecked();
            return detailArrayList;
        }, executor);


        //2、计算总价
        CompletableFuture<List<CartInfo>> totalAmountFuture  = listCompletableFuture.whenCompleteAsync((res, exp) -> {
            ArrayList<CartInfo> infos = new ArrayList<>();
            for (CartInfo cartInfo : res) {
                //总价 = 数量 * 单价
                Integer skuNum = totalNum[0].addAndGet(cartInfo.getSkuNum());//叠加数量
                //3、查询最新价格
                RequestContextHolder.setRequestAttributes(requestAttributes);
                BigDecimal skuPrice = skuInfoFeignClient.getSkuPrice(cartInfo.getSkuId());
                cartInfo.setOrderPrice(skuPrice);
                BigDecimal multiply = skuPrice.multiply(new BigDecimal(skuNum.toString()));
                totalAmount[0] = totalAmount[0].add(multiply);
                infos.add(cartInfo);
            }
            map.put("detailArrayList",infos);
            map.put("totalNum",totalNum[0]);
            map.put("totalAmount",totalAmount[0]);
        }, executor);


        //4、远程查询用户的所有收货地址列表
        CompletableFuture<List<UserAddress>> priceAndNumFuture = CompletableFuture.supplyAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<UserAddress> userAddressList = userFeignClient.getCurrentUserAddress();
            map.put("userAddressList",userAddressList);
            return userAddressList;
        }, executor);

        //3、页面需要tradeNo,页面用来做防重复提交
        CompletableFuture<Void> tokenFuture = CompletableFuture.runAsync(() -> {
            String token = UUID.randomUUID().toString().replace("-", "");
            ValueOperations<String, String> ops = redisTemplate.opsForValue();
            ops.set(RedisConst.USER_UNREPEAT_TOKEN + userId, token, RedisConst.USER_UNREPEAT_TOKEN_TTL, TimeUnit.SECONDS);
            map.put("tradeNo", token);
        });

        CompletableFuture
                .allOf(listCompletableFuture,totalAmountFuture,priceAndNumFuture,tokenFuture)
                .join(); //所有都完成

        return map;
    }
}
